// SPDX-License-Identifier: Apache-2.0
//
// Copyright © 2017 Trust Wallet.

use tw_encoding::hex;
use tw_encoding::hex::{DecodeHex, ToHex};
use tw_evm::ffi::biz::{
    tw_biz_encode_execute_with_passkey_session_call, tw_biz_encode_passkey_session_nonce,
    tw_biz_encode_register_session_call, tw_biz_encode_remove_session_call,
    tw_biz_get_encoded_hash, tw_biz_get_signed_hash,
};
use tw_keypair::test_utils::tw_public_key_helper::TWPublicKeyHelper;
use tw_keypair::tw::PublicKeyType;
use tw_memory::test_utils::tw_data_helper::TWDataHelper;
use tw_memory::test_utils::tw_string_helper::TWStringHelper;
use tw_number::U256;
use tw_proto::serialize;
use tw_proto::Biz::Proto::mod_ExecuteWithPasskeySessionInput::Execution;
use tw_proto::Biz::Proto::ExecuteWithPasskeySessionInput;

const ONE_ETH: u64 = 1_000_000_000_000_000_000;

#[test]
fn test_get_encoded_hash_ffi() {
    let chain_id = U256::from(31337u64).to_big_endian();
    let chain_id = TWDataHelper::create(chain_id.to_vec());

    let code_address = TWStringHelper::create("0x2e234DAe75C793f67A35089C9d99245E1C58470b");
    let code_name = TWStringHelper::create("Biz");
    let code_version = TWStringHelper::create("v1.0.0");
    let type_hash = TWStringHelper::create(
        "0x4f51e7a567f083a31264743067875fc6a7ae45c32c5bd71f6a998c4625b13867",
    );
    let domain_separator_hash = TWStringHelper::create(
        "0xd87cd6ef79d4e2b95e15ce8abf732db51ec771f1ca2edccf22a46c729ac56472",
    );
    let sender = TWStringHelper::create("0x174a240e5147D02dE4d7724D5D3E1c1bF11cE029");
    let user_op_hash = TWStringHelper::create(
        "0xf177858c1c500e51f38ffe937bed7e4d3a8678725900be4682d3ce04d97071eb",
    );

    let encoded_hash = TWDataHelper::wrap(unsafe {
        tw_biz_get_encoded_hash(
            chain_id.ptr(),
            code_address.ptr(),
            code_name.ptr(),
            code_version.ptr(),
            type_hash.ptr(),
            domain_separator_hash.ptr(),
            sender.ptr(),
            user_op_hash.ptr(),
        )
    });
    assert_eq!(
        hex::encode(encoded_hash.to_vec().unwrap(), true),
        "0xc63891abc38f7a991f89ad7cb6d7e53543627b0536c3f5e545b736756c971635"
    );
}

#[test]
fn test_get_signed_hash_ffi() {
    let hash = TWStringHelper::create(
        "0xc63891abc38f7a991f89ad7cb6d7e53543627b0536c3f5e545b736756c971635",
    );
    let private_key = TWStringHelper::create(
        "0x947dd69af402e7f48da1b845dfc1df6be593d01a0d8274bd03ec56712e7164e8",
    );
    let signed_hash =
        TWDataHelper::wrap(unsafe { tw_biz_get_signed_hash(hash.ptr(), private_key.ptr()) });
    assert_eq!(hex::encode(signed_hash.to_vec().unwrap(), true), "0xa29e460720e4b539f593d1a407827d9608cccc2c18b7af7b3689094dca8a016755bca072ffe39bc62285b65aff8f271f20798a421acf18bb2a7be8dbe0eb05f81c");
}

#[test]
fn test_register_session_ffi() {
    let public_key = TWPublicKeyHelper::with_hex(
        "0x041c05286fe694493eae33312f2d2e0d0abeda8db76238b7a204be1fb87f54ce4228fef61ef4ac300f631657635c28e59bfb2fe71bce1634c81c65642042f6dc4d",
        PublicKeyType::Nist256p1Extended
    );
    let valid_until = TWDataHelper::create(U256::from(86_401_u64).to_big_endian_compact());
    let data = TWDataHelper::wrap(unsafe {
        tw_biz_encode_register_session_call(public_key.ptr(), valid_until.ptr())
    });
    assert_eq!(
        data.to_vec().unwrap().to_hex(),
        "826491fb000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000151810000000000000000000000000000000000000000000000000000000000000041041c05286fe694493eae33312f2d2e0d0abeda8db76238b7a204be1fb87f54ce4228fef61ef4ac300f631657635c28e59bfb2fe71bce1634c81c65642042f6dc4d00000000000000000000000000000000000000000000000000000000000000"
    );
}

#[test]
fn test_remove_session_ffi() {
    let public_key = TWPublicKeyHelper::with_hex(
        "0x041c05286fe694493eae33312f2d2e0d0abeda8db76238b7a204be1fb87f54ce4228fef61ef4ac300f631657635c28e59bfb2fe71bce1634c81c65642042f6dc4d",
        PublicKeyType::Nist256p1Extended
    );
    let data = TWDataHelper::wrap(unsafe { tw_biz_encode_remove_session_call(public_key.ptr()) });
    assert_eq!(
        data.to_vec().unwrap().to_hex(),
        "e1c06abd00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000041041c05286fe694493eae33312f2d2e0d0abeda8db76238b7a204be1fb87f54ce4228fef61ef4ac300f631657635c28e59bfb2fe71bce1634c81c65642042f6dc4d00000000000000000000000000000000000000000000000000000000000000"
    );
}

#[test]
fn test_encode_passkey_nonce_ffi() {
    let nonce = TWDataHelper::create(U256::from(123_u64).to_big_endian_compact());
    let data = TWDataHelper::wrap(unsafe { tw_biz_encode_passkey_session_nonce(nonce.ptr()) });
    assert_eq!(
        data.to_vec().unwrap().to_hex(),
        "00000000000000000000000000000000050041d6a66939a8000000000000007b"
    );
}

#[test]
fn test_execute_with_passkey_session_ffi() {
    let passkey_signature = "0x00000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000017000000000000000000000000000000000000000000000000000000000000000188458d3b608d1195be386bc6017e389d46624b50cb450792fb8c91e84e3e1ff912aabc684a855da9e83cb6cafe74950dcf6d81e8b3b2b7a5437abc1762ca736d000000000000000000000000000000000000000000000000000000000000002549960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008a7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22343368697353614c5553757a6547785330662d705443686731736334616873307949645f7162463141634d222c226f726967696e223a2268747470733a2f2f7369676e2e636f696e626173652e636f6d222c2263726f73734f726967696e223a66616c73657d00000000000000000000000000000000000000000000";
    let input = ExecuteWithPasskeySessionInput {
        executions: vec![
            Execution {
                address: "0x0000000000000000000000000000000000000001".into(),
                amount: U256::from(ONE_ETH).to_big_endian_compact().into(),
                payload: Default::default(),
            },
            Execution {
                address: "0x0000000000000000000000000000000000000002".into(),
                amount: U256::from(ONE_ETH).to_big_endian_compact().into(),
                payload: Default::default(),
            },
            Execution {
                address: "0x0000000000000000000000000000000000000003".into(),
                amount: U256::from(ONE_ETH).to_big_endian_compact().into(),
                payload: Default::default(),
            },
        ],
        valid_after: 0,
        valid_until: 61,
        passkey_signature: passkey_signature.decode_hex().unwrap().into(),
    };
    let input = TWDataHelper::create(serialize(&input).unwrap());

    let encoded =
        TWDataHelper::wrap(unsafe { tw_biz_encode_execute_with_passkey_session_call(input.ptr()) });
    let expected = "0x38892f8800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000003d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000de0b6b3a76400000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020100000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000017000000000000000000000000000000000000000000000000000000000000000188458d3b608d1195be386bc6017e389d46624b50cb450792fb8c91e84e3e1ff912aabc684a855da9e83cb6cafe74950dcf6d81e8b3b2b7a5437abc1762ca736d000000000000000000000000000000000000000000000000000000000000002549960de5880e8c687434170f6476605b8fe4aeb9a28632c7995cf3ba831d97630500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008a7b2274797065223a22776562617574686e2e676574222c226368616c6c656e6765223a22343368697353614c5553757a6547785330662d705443686731736334616873307949645f7162463141634d222c226f726967696e223a2268747470733a2f2f7369676e2e636f696e626173652e636f6d222c2263726f73734f726967696e223a66616c73657d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
    assert_eq!(encoded.to_vec().unwrap().to_hex_prefixed(), expected);
}
